package common

import (
	"reflect"
	"strings"
	"unsafe"
)

type KeyValue struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

type KeyValues struct {
	Data []KeyValue
}

type ValueScore struct {
	Score *float64 `json:"score"`
	Value string   `json:"value"`
}

type RangeScore struct {
	MinScore *float64 `json:"min_score"`
	MaxScore *float64 `json:"max_score"`
}

type ClusterConfig struct {
	Hosts []string `json:"hosts"`
	Index *int     `json:"index"`
}

type KeyValueScore struct {
	Id    uint16
	Score float64
	Key   []byte
	Value []byte
}

func GetKeyValue(path []byte) ([]byte, []byte) {
	e := len(path)
	s := len(path) - 1
	for s > 0 {
		if path[s] == '/' {
			break
		}
		s--
	}
	value := path[s+1 : e]
	e = s
	s = e - 1
	for s > 0 {
		if path[s] == '/' {
			break
		}
		s--
	}
	key := path[s+1 : e]
	return key, value
}

func GetKey(path []byte) []byte {
	e := len(path)
	s := len(path) - 1
	for s > 0 {
		if path[s] == '/' {
			break
		}
		s--
	}
	return path[s+1 : e]
}

// BytesToString converts byte slice to a string without memory allocation.
//
// Note it may break if the implementation of string or slice header changes in the future go versions.
func BytesToString(b []byte) string {
	/* #nosec G103 */
	return *(*string)(unsafe.Pointer(&b))
}

// StringToBytes converts string to a byte slice without memory allocation.
//
// Note it may break if the implementation of string or slice header changes in the future go versions.
func StringToBytes(s string) (b []byte) {
	/* #nosec G103 */
	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
	/* #nosec G103 */
	bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))

	bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
	return b
}

func BuildKVJson(builder *strings.Builder, keys [][]byte, values [][]byte, size int) {
	builder.Reset()
	builder.Write([]byte("["))
	cnt := 0
	for i := 0; i < len(keys); i++ {
		if values[i] == nil {
			continue
		}
		cnt++
		builder.Write([]byte("{\"key\":\""))
		builder.Write(keys[i])
		builder.Write([]byte("\",\"value\":\""))
		builder.Write(values[i])
		if cnt < size {
			builder.Write([]byte("\"},"))
		} else {
			builder.Write([]byte("\"}"))
		}
	}
	builder.Write([]byte("]"))
}

func BuildVsJson(builder *strings.Builder, values []string, scores []string) {
	builder.Reset()
	builder.Write([]byte("["))
	size := len(values)
	for i := 0; i < size; i++ {
		builder.Write([]byte("{\"score\":" + scores[i]))
		builder.Write([]byte(",\"value\":\"" + values[i]))
		if i < size-1 {
			builder.Write([]byte("\"},"))
		} else {
			builder.Write([]byte("\"}"))
		}
	}
	builder.Write([]byte("]"))
}
